package ai.people.core.web.exception.handler;

import ai.people.netmon.framework.exception.enums.CommonEnum;
import ai.people.netmon.framework.exception.enums.FileExceptionEnum;
import ai.people.netmon.framework.exception.enums.ParamExceptionEnum;
import ai.people.netmon.framework.model.response.Result;
import ai.people.netmon.framework.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理程序
 *
 * @author yuanqinglong
 * @date 2022/2/15 17:34
 */
@Order(30)
@RestControllerAdvice
public class GlobalExceptionHandler {

    Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 文件大小异常处理程序
     *
     * @param maxUploadSizeExceededException e
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public <T> Result<T> maxUploadSizeExceededException(MaxUploadSizeExceededException maxUploadSizeExceededException) {
        maxUploadSizeExceededException.printStackTrace();
        //记录日志
        logger.error("catch exception:{}", maxUploadSizeExceededException.getMessage());
        return ResultUtil.error(FileExceptionEnum.FILE_SIZE_LIMIT);
    }


    /**
     * 非法参数异常
     *
     * @param illegalArgumentException 非法参数异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public <T> Result<T> illegalArgumentException(IllegalArgumentException illegalArgumentException) {
        illegalArgumentException.printStackTrace();
        //记录日志
        logger.error("catch exception:{}", illegalArgumentException.getMessage());
        return ResultUtil.error(ParamExceptionEnum.PARAMETER_PARSING_EXCEPTION);
    }


    /**
     * 数字格式异常
     *
     * @param numberFormatException 数字格式异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public <T> Result<T> exceptionHandler(HttpMessageNotReadableException numberFormatException) {
        Throwable rootCause = numberFormatException.getRootCause();
        if (rootCause instanceof NumberFormatException) {
            return exceptionHandler((NumberFormatException) rootCause);
        }
        //记录日志
        logger.error("catch exception", numberFormatException);
        return ResultUtil.error(ParamExceptionEnum.PARAMETER_PARSING_EXCEPTION);
    }


    /**
     * 数字格式异常
     *
     * @param numberFormatException 数字格式异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(NumberFormatException.class)
    public <T> Result<T> exceptionHandler(NumberFormatException numberFormatException) {
        //记录日志
        logger.error("catch exception", numberFormatException);
        ParamExceptionEnum exceptionEnum = ParamExceptionEnum.PARAMETER_VALUE_OUT_OF_RANGE;
        return ResultUtil.error(exceptionEnum.getCode(), "{" + numberFormatException.getMessage() + "}" + exceptionEnum.getMessage());
    }


    /**
     * 异常类型不匹配
     *
     * @param typeMismatchException 异常类型不匹配
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(TypeMismatchException.class)
    public <T> Result<T> typeMismatchException(TypeMismatchException typeMismatchException) {
        typeMismatchException.printStackTrace();
        //记录日志
        logger.error("catch exception:{}", typeMismatchException.getMessage());
        return ResultUtil.error(ParamExceptionEnum.PARAMETER_TYPE_MISMATCH);
    }

    /**
     * http媒体类型不支持异常处理程序
     *
     * @param httpMediaTypeNotSupportedException 异常类型不匹配
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public <T> Result<T> httpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException httpMediaTypeNotSupportedException) {
        //记录日志
        logger.error("catch exception:", httpMediaTypeNotSupportedException);
        CommonEnum unsupportedMediaType = CommonEnum.UNSUPPORTED_MEDIA_TYPE;
        return ResultUtil.error(unsupportedMediaType.getCode(), unsupportedMediaType.getMessage() + ":" + httpMediaTypeNotSupportedException.getContentType());
    }


    /**
     * 方法参数无效异常
     *
     * @param methodArgumentNotValidException 无效异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public <T> Result<T> methodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        //记录日志
        String errorMsg = methodArgumentNotValidException.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(","));
        // TODO: 2022/1/7 返回参数校验失败错误码
        return ResultUtil.error(ParamExceptionEnum.INSUFFICIENT_PARAMETERS.getCode(), errorMsg);
    }

    /**
     * 异常处理程序
     *
     * @param constraintViolationException 违反校验约束异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public <T> Result<T> constraintViolationException(ConstraintViolationException constraintViolationException) {
        //记录日志
        String errorMsg = constraintViolationException.getConstraintViolations().stream().map(ConstraintViolation::getMessageTemplate).collect(Collectors.joining(","));
        return ResultUtil.error(ParamExceptionEnum.PARAMETER_PARSING_EXCEPTION.getCode(), errorMsg);
    }


    /**
     * http请求方法不支持异常
     *
     * @param httpRequestMethodNotSupportedException 方法不支持异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public <T> Result<T> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException httpRequestMethodNotSupportedException) {
        String requestMethod = httpRequestMethodNotSupportedException.getMethod();
        logger.error("catch exception", httpRequestMethodNotSupportedException);
        return ResultUtil.error(CommonEnum.REQUEST_METHOD_TYPE_ERROR.getCode(), CommonEnum.REQUEST_METHOD_TYPE_ERROR.getMessage() + requestMethod + "、或参数错误");
    }


    /**
     * 缺少Servlet 请求参数异常
     *
     * @param missingServletRequestParameterException 方法不支持异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public <T> Result<T> methodNotSupportedException(MissingServletRequestParameterException missingServletRequestParameterException) {
        logger.error("catch missingServletRequestParameterException", missingServletRequestParameterException);
        return ResultUtil.error(ParamExceptionEnum.INSUFFICIENT_PARAMETERS);
    }


    /**
     * 缺少Servlet 请求参数异常
     *
     * @param missingServletRequestPartException 方法不支持异常
     * @return {@link Result}<{@link T}>
     */
    @ExceptionHandler(MissingServletRequestPartException.class)
    public <T> Result<T> methodNotSupportedException(MissingServletRequestPartException missingServletRequestPartException) {
        logger.error("catch missingServletRequestPartException", missingServletRequestPartException);
        return ResultUtil.error(ParamExceptionEnum.INSUFFICIENT_PARAMETERS);
    }

    //
    ///**
    // * feign异常处理程序
    // *
    // * @param feignException 异常
    // * @return {@link Result}<{@link T}>
    // */
    //@ExceptionHandler(FeignException.class)
    //public <T> Result<T> feignException(FeignException feignException) {
    //    String message = feignException.getMessage();
    //    logger.error("系统异常", feignException);
    //    if (message.contains("error_description")) {
    //        return ResultUtil.error(AuthExceptionEnum.AUTH_ACCOUNT_ERROR);
    //    }
    //    return ResultUtil.error(CommonEnum.SERVER_ERROR);
    //}


}
